package service

import (
	"context"
	"math"
	"math/rand"
	"strconv"
	"time"
	"wespy-http-go/app/activity/common/actreward"
	"wespy-http-go/def"

	"github.com/sirupsen/logrus"

	"wespy-http-go/app/activity/2025/summer_drink_car/conf"
	"wespy-http-go/app/activity/2025/summer_drink_car/store"
	"wespy-http-go/app/activity/common/acterror"
	"wespy-http-go/app/activity/common/actinfo"
	"wespy-http-go/app/activity/common/actlogger"
	"wespy-http-go/app/activity/common/actmsg"
	"wespy-http-go/app/activity/common/actstore"
	"wespy-http-go/app/activity/common/actutil"
	collect_chip "wespy-http-go/app/activity/widget/collect_chip/service"
	rankService "wespy-http-go/app/activity/widget/rank/service"
	"wespy-http-go/helper"
	"wespy-http-go/pkg/weconfig/wenamespace/weactivity"
)

// SendFlyer 发送传单
func SendFlyer(c context.Context, req *store.SendFlyerReq) (*store.SendFlyerRsp, error) {
	entry := actlogger.GetLogger(c)
	actInfo := actinfo.GetValidActByUid(conf.ActId, req.Uid)
	if actInfo == nil {
		return nil, acterror.NewCustomError(actmsg.ActTimeErr)
	}
	actConfig := conf.GetActConfig(actInfo)
	if actConfig == nil {
		return nil, acterror.NewCustomError(actmsg.ConfigErr)
	}
	if !helper.InArrayInt(req.Number, actConfig.ValidFlyerNumber) {
		return nil, acterror.NewCustomError(actmsg.ParamsErr)
	}

	lockKey := store.GetUserLockKey(req.ActId, req.Uid)
	lockRes := actstore.TryLockOnce(lockKey, 2)
	if lockRes.Failed() {
		return nil, acterror.NewCustomError(actmsg.LockErr)
	}
	defer lockRes.Unlock()

	_, err := collect_chip.CostUserChip(req.ActId, req.Uid, conf.ChipIdFlyer, req.Number, &collect_chip.AddCollectChipExtra{
		Source:       "发送传单",
		AutoPurchase: req.AutoPurchase,
	})
	if err != nil {
		return nil, err
	}

	num, err := fillTable(entry, actConfig, req.Uid, req.Number, actInfo.GetActCurrentTime())
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car SendFlyer fillTable err")
		return nil, err
	}

	// 增加排行榜积分（口碑积分）
	err = handleSendFlyerRank(entry, actInfo, req.Uid, req.Number)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car SendFlyer handleSendFlyerRank err")
		// 不返回错误，避免影响主流程
	}

	entry.WithField("num", num).Infoln("summer_drink_car SendFlyer success")
	return &store.SendFlyerRsp{}, nil
}

// GetTables 获取桌子信息
func GetTables(c context.Context, req *actutil.CommonReq) (*store.GetTableRsp, error) {
	entry := actlogger.GetLogger(c)
	resp := new(store.GetTableRsp)
	actId, uid := req.ActId, req.Uid
	actInfo := actinfo.GetValidActByUid(actId, uid)
	if actInfo == nil {
		return nil, acterror.NewCustomError(actmsg.ActTimeErr)
	}
	actConfig := conf.GetActConfig(actInfo)
	if actConfig == nil {
		return nil, acterror.NewCustomError(actmsg.ConfigErr)
	}

	tableDtoList, err := store.GetTableList(actId, uid, 0, -1)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car GetTables GetTableList err")
		return nil, err
	}
	tableList := make([]*store.TableInfo, 0, actConfig.TableNumber)
	for _, table := range tableDtoList {
		// 将时间戳转换为 "2020-02-01 12:00" 格式
		timestampStr := time.Unix(int64(table.Timestamp), 0).Format(def.FormatTimeWithSeparator)
		tableList = append(tableList, &store.TableInfo{
			Timestamp: timestampStr,
			NpcId:     table.Member%actConfig.NpcNumber + 1,
		})
	}
	// 使用空桌子填充
	for len(tableList) < actConfig.TableNumber {
		tableList = append(tableList, &store.TableInfo{})
	}
	refreshTimestamp := math.MaxInt
	for _, item := range tableDtoList {
		if item.Timestamp > 0 && item.Timestamp < refreshTimestamp {
			refreshTimestamp = item.Timestamp
		}
	}
	var refreshTimestampStr string
	if refreshTimestamp == math.MaxInt || refreshTimestamp == 0 {
		refreshTimestampStr = ""
	} else {
		refreshTimestampStr = time.Unix(int64(refreshTimestamp), 0).Format(def.FormatTimeWithSeparator)
	}
	resp.RefreshTimestamp = refreshTimestampStr
	resp.List = tableList

	resp.MealingNum = len(tableDtoList)
	resp.PendingNum, err = store.GetWaitNum(actId, uid)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car GetTables GetWaitNum err")
		return nil, err
	}
	resp.DeskNum = actConfig.TableNumber
	checkoutInfo, err := store.GetCheckoutInfo(actId, uid)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car GetTables GetCheckoutInfo err")
		return nil, err
	}
	resp.TipNum = checkoutInfo[store.CheckoutFieldTipNum]
	resp.ReputationScore = checkoutInfo[store.CheckoutFieldReputationScore]
	return resp, nil
}

// CheckoutTables 结算桌子
func CheckoutTables(c context.Context, req *actutil.CommonReq) (*store.CheckoutTablesRsp, error) {
	entry := actlogger.GetLogger(c)
	res := &store.CheckoutTablesRsp{}
	actInfo := actinfo.GetValidActByUid(req.ActId, req.Uid)
	if actInfo == nil {
		return nil, acterror.NewCustomError(actmsg.ActTimeErr)
	}
	actConfig := conf.GetActConfig(actInfo)
	if actConfig == nil {
		return nil, acterror.NewCustomError(actmsg.ConfigErr)
	}
	num, err := CheckoutTablesSrv(entry, actConfig, req.Uid, actInfo.GetActCurrentTime())
	if err != nil {
		return nil, err
	}
	res.CheckoutNum = num
	return res, nil
}

// CheckoutTablesSrv 结算桌子服务
func CheckoutTablesSrv(entry *logrus.Entry, actConfig *conf.ActConfig, uid int, now time.Time) (int, error) {
	actID := conf.ActId
	lock := actstore.TryLockWithRetry(store.GetUserLockKey(conf.ActId, uid), 5)
	if lock.Failed() {
		entry.Warnln("summer_drink_car CheckoutTablesSrv lock fail")
		return 0, acterror.NewCustomError(actmsg.LockErr)
	}
	defer lock.Unlock()

	members, err := store.GetEndedTable(actID, uid, int(now.Unix()))
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car CheckoutTablesSrv GetEndedTable err")
		return 0, err
	}
	if len(members) == 0 {
		return 0, nil
	}
	entry.Infoln("summer_drink_car CheckoutTablesSrv start")
	if err = store.DelUserInTable(actID, uid, members); err != nil {
		entry.WithError(err).Errorln("summer_drink_car CheckoutTablesSrv DelUserInTable err")
		return 0, err
	}
	_, err = fillTable(entry, actConfig, uid, 0, now)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car CheckoutTablesSrv fillTable err")
		return 0, err
	}
	calculateBenefit(entry, actConfig, uid, len(members))
	return len(members), nil
}

// calculateBenefit 计算收益
func calculateBenefit(entry *logrus.Entry, config *conf.ActConfig, uid, count int) {
	tipNum := count * config.TipNum
	reputationScore := count * config.ReputationScore
	curTipNum, err := store.IncrCheckoutInfoField(conf.ActId, uid, store.CheckoutFieldTipNum, tipNum)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car calculateBenefit incr tip num err")
	}
	entry = entry.WithField("cur_tip_num", curTipNum)
	curReputationScore, err := store.IncrCheckoutInfoField(conf.ActId, uid, store.CheckoutFieldReputationScore, reputationScore)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car calculateBenefit incr reputation score err")
	}

	entry.WithField("cur_reputation_score", curReputationScore).Infoln("summer_drink_car calculateBenefit end")
}

// fillTable 填充桌子
func fillTable(entry *logrus.Entry, actConfig *conf.ActConfig, uid, needJoinNum int, now time.Time) (num int, err error) {
	currNum, err := store.IncrWaitNum(conf.ActId, uid, needJoinNum)
	if err != nil {
		return
	}
	if currNum <= 0 {
		return 0, nil
	}
	totalNum := currNum

	unlockAdvanced := isUnlockAdvanced(conf.ActId, uid)
	duration := actConfig.NormalDuration
	if unlockAdvanced {
		duration = actConfig.AdvancedDuration
	}
	endTime := int(now.Add(time.Second * time.Duration(duration)).Unix())
	inUseNum, err := store.GetTableNum(conf.ActId, uid)
	if err != nil {
		return 0, err
	}
	leftTableNum := actConfig.TableNumber - inUseNum
	if leftTableNum <= 0 {
		return 0, nil
	}
	waitForAddMap := make(map[int]int)
	// 有空桌子，有多余需要加的人： 插入npc
	for totalNum > 0 && leftTableNum > 0 {
		randomUid := rand.Intn(math.MaxInt32)
		waitForAddMap[randomUid] = endTime
		totalNum--
		leftTableNum--
	}
	// 填充座位
	deductNum := currNum - totalNum
	entry = entry.WithField("deduct_num", deductNum)
	_, err = store.DeductWaitNum(conf.ActId, uid, deductNum)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car fillTable DeductWaitNum err")
		return
	}
	entry.Infoln("summer_drink_car fillTable end")
	err = store.AddTable(conf.ActId, uid, waitForAddMap)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car fillTable AddTable err")
		return 0, err
	}
	// 创建延迟任务，定时结算
	actutil.CreateDeferTask(conf.ActId, conf.DeferTaskCheckout, duration, &store.CheckoutTask{
		Uid:       uid,
		Timestamp: endTime,
	})
	return deductNum, nil
}

// CheckoutTip 领取小费和口碑分
func CheckoutTip(c context.Context, req *store.CheckoutTipReq) (*store.CheckoutTipRsp, error) {
	entry := actlogger.GetLogger(c)
	rsp := &store.CheckoutTipRsp{}
	actInfo := actinfo.GetValidActByUid(conf.ActId, req.Uid)
	if actInfo == nil {
		return nil, acterror.NewCustomError(actmsg.ActTimeErr)
	}
	actConfig := conf.GetActConfig(actInfo)
	if actConfig == nil {
		return nil, acterror.NewCustomError(actmsg.ConfigErr)
	}

	lockKey := store.GetUserLockKey(req.ActId, req.Uid)
	lockRes := actstore.TryLockWithRetry(lockKey, 2)
	if lockRes.Failed() {
		return nil, acterror.NewCustomError(actmsg.LockErr)
	}
	defer lockRes.Unlock()

	checkoutInfo, err := store.GetCheckoutInfo(req.ActId, req.Uid)
	if err != nil {
		return nil, err
	}
	tipNum := checkoutInfo[store.CheckoutFieldTipNum]
	reputationScore := checkoutInfo[store.CheckoutFieldReputationScore]
	if tipNum <= 0 && reputationScore <= 0 {
		return rsp, nil
	}
	entry = entry.WithField("tip_num", tipNum).WithField("reputation_score", reputationScore)
	err = store.ClearCheckoutInfo(req.ActId, req.Uid)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car CheckoutTip ClearCheckoutInfo err")
		return nil, err
	}
	rewards := make([]*actreward.RewardInfo, 0)
	if tipNum > 0 {
		rewards = append(rewards, &actreward.RewardInfo{
			ActId:      req.ActId,
			RewardType: actreward.RewardTypeCollectChip,
			RewardId:   conf.ChipIdTipNum,
			RewardVal:  tipNum,
		})
	}
	if reputationScore > 0 {
		rewards = append(rewards, &actreward.RewardInfo{
			ActId:      req.ActId,
			RewardType: actreward.RewardTypeCollectChip,
			RewardId:   conf.ChipIdReputationScore,
			RewardVal:  reputationScore,
		})
	}
	err = actreward.SendRewards(req.Uid, rewards, &actreward.ExtraInfo{
		ActId:      req.ActId,
		ActName:    actInfo.Name,
		ChipSource: "领取小费",
	})
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car CheckoutTip SendRewards err")
	}
	rsp.TipNum = tipNum
	rsp.ReputationScore = reputationScore
	return rsp, nil
}

// isUnlockAdvanced 是否解锁高级功能
func isUnlockAdvanced(actId, uid int) bool {
	num := collect_chip.GetUserChip(actId, uid, conf.ChipIdBuyFlag)
	return num > 0
}

// handleSendFlyerRank 处理发送传单的排行榜积分增加
func handleSendFlyerRank(entry *logrus.Entry, actInfo *weactivity.Activity, uid, flyerCount int) error {
	// 获取排行榜配置（口碑排行榜 rankId=1）
	rankConfig := GetRankConfig(actInfo, 1)
	if rankConfig == nil {
		entry.Errorln("summer_drink_car handleSendFlyerRank rankConfig is nil")
		return nil // 不返回错误，避免影响主流程
	}

	now := actInfo.GetActCurrentTime()
	member := strconv.Itoa(uid)

	// 每发送1张传单增加1点口碑积分
	score, err := rankService.IncrRankValueWithTime(actInfo, rankConfig.Type, rankConfig.PeriodType, member, flyerCount, now)
	if err != nil {
		entry.WithError(err).Errorln("summer_drink_car handleSendFlyerRank IncrRankValueWithTime err")
		return err
	}

	entry.WithField("uid", uid).WithField("flyer_count", flyerCount).
		WithField("score", score).Infoln("summer_drink_car handleSendFlyerRank success")
	return nil
}
